#!/usr/bin/env python3
"""A quick recap of the last few minutes of the live call, for Aux's hover button on the orb.

  aux-recap [--minutes 5 | --seconds 60] [--env prod|staging|dev] [--call <id>]   # --call: a stored call, for testing

Pulls the recent speech from the Tuple capture, has Claude (a fast model, no tools, no session) write a
few bullets, and prints one JSON object: {"title","body","seconds","lines","call","through"}; on failure
{"error": "..."} with exit 1. A window of a minute or less gets the gist in one or two bullets from the
fastest model: Aux refreshes that one in the background through a call, so the 60s button is instant.
"through" is the time of the last line summarised (for telling whether a warm recap is current).
"""
import argparse
import json
import subprocess
import sys
from pathlib import Path

# Inside an app bundle (Tuple.app/Contents/Helpers/Tuple Aux.app) a __pycache__ write is macOS's
# "python3 was prevented from modifying apps" prompt; the import never needs one.
sys.dont_write_bytecode = True
sys.path.insert(0, str(Path(__file__).resolve().parent))
from aux_context import CLIS, AUX, capture, recent_speech, resolve_env  # noqa: E402

MODEL = "sonnet"
QUICK_MODEL = "haiku"   # windows of a minute or less
TIMEOUT = 75


def fail(msg):
    print(json.dumps({"error": msg}))
    return 1


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--minutes", type=int, default=5)
    ap.add_argument("--seconds", type=int, help="the window in seconds; overrides --minutes")
    ap.add_argument("--env", choices=CLIS)
    ap.add_argument("--call")
    a = ap.parse_args()

    env, cli, call = resolve_env(a.env)
    if a.call:
        call = a.call
    if not cli:
        return fail("No Tuple CLI installed.")
    if not call:
        return fail("No live call to recap.")
    seconds = a.seconds or a.minutes * 60
    quick = seconds <= 60
    span = f"{seconds} seconds" if seconds < 120 else f"{seconds // 60} minutes"
    title = f"Last {span}"
    recs = capture(cli, call)
    speech = [r for r in recs if r.get("type") == "transcription_finished"]
    through = speech[-1].get("time") if speech else None
    lines = recent_speech(recs, seconds / 60)
    if not lines:
        print(json.dumps({"title": title, "body": f"Nothing was said in the last {span}.",
                          "seconds": seconds, "lines": 0, "call": call, "through": through}))
        return 0

    if quick:
        prompt = (
            f"Below is the last {span} of speech from a live Tuple call the operator is on. They glanced away and "
            "want the gist of what was just said, readable in three seconds: one or two Markdown bullets, each under "
            "fifteen words, leading with the point in **bold**. Name people by first name. Bullets only.\n\n"
            + "\n".join(lines)
        )
        return answer(prompt, QUICK_MODEL, title, seconds, lines, call, through)
    prompt = (
        f"Below is the last {span} of speech from a live Tuple call the operator is on. Write the recap "
        "they would want if they had just tuned back in: three to six short Markdown bullets, most important first. "
        "Decisions, open questions, who is waiting on whom, anything the operator has to act on. Name people by first "
        "name. Lead each bullet with its point in **bold** (the decision, or who does what by when), then a short "
        "sentence of detail. No preamble, no heading, no closing line; bullets only.\n\n" + "\n".join(lines)
    )
    return answer(prompt, MODEL, title, seconds, lines, call, through)


def answer(prompt, model, title, seconds, lines, call, through):
    cmd = ["claude", "-p", "--model", model, "--tools", "", "--no-session-persistence", "--strict-mcp-config",
           "--output-format", "text", prompt]
    try:
        p = subprocess.run(cmd, cwd=str(AUX), capture_output=True, text=True, timeout=TIMEOUT, stdin=subprocess.DEVNULL)
    except FileNotFoundError:
        return fail("claude is not installed.")
    except subprocess.TimeoutExpired:
        return fail("The recap took too long.")
    body = p.stdout.strip()
    if p.returncode != 0 or not body:
        # Claude prints some errors on stdout ("Invalid API key") and warnings on stderr ("⚠ …", "Warning: …"):
        # the reason is the last line that isn't a warning, stdout's first.
        def reasons(text):
            return [l.strip() for l in text.splitlines() if l.strip() and not l.strip().startswith(("⚠", "Warning:"))]
        lines = reasons(p.stdout) or reasons(p.stderr)
        return fail((lines or ["Claude returned nothing."])[-1][:200])
    print(json.dumps({"title": title, "body": body, "seconds": seconds, "lines": len(lines), "call": call,
                      "through": through}))
    return 0


if __name__ == "__main__":
    sys.exit(main())
